Skip to content

feat: cohort CSV sync endpoint and cohort summary on segments - #8294

Merged
Zaimwa9 merged 0 commit into
mainfrom
feat/cohort-csv-sync
Aug 25, 2026
Merged

feat: cohort CSV sync endpoint and cohort summary on segments#8294
Zaimwa9 merged 0 commit into
mainfrom
feat/cohort-csv-sync

Conversation

@Zaimwa9

@Zaimwa9 Zaimwa9 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Thanks for submitting a PR! Please check the boxes below:

  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Adds the API surface the dashboard needs to create segments from a CSV of identifiers, on top of the cohort CRUD from #8248.

CSV sync endpoint

  • POST /api/v1/environments/{api_key}/cohorts/{id}/sync-csv/: multipart upload with file, identifier_column (0-based, defaults to the first column) and has_header (defaults to true).
  • Declarative replace: the uploaded identifiers become the cohort's desired membership. Responds 202 with {version, added, removed, unchanged, ignored: {empty, duplicates, too_long}} and queues the membership delta application inside the transaction, with a row lock on the cohort and a version bump.
  • The file is parsed and discarded, never stored. Files over 10MB are rejected with 413.

Cohort creation

  • POST .../cohorts/ now accepts segment metadata (custom fields), applied to the managed segment.

Segments API

  • Segment payloads carry a read-only cohort summary (id, environment, source_type, version, deletion_requested_at), prefetched on the list view. This lets the dashboard tag CSV segments, route their deletion through the cohorts endpoint, and grey out segments awaiting drain.

Observability

  • New metrics flagsmith_cohorts_csv_syncs_total and flagsmith_cohorts_csv_sync_identifiers, new cohorts.csv.synced event, both documented in the observability catalogues.

How did you test this code?

  • Unit tests for the CSV extraction and sync services (delta semantics, duplicates, empty rows, too-long identifiers, version bumps), the sync-csv view (validation, size cap, permissions), metadata on create, and the segment list cohort summary.
  • Manually through the dashboard drawer (stacked frontend branch): created cohorts from CSV files, verified membership rows and delta counts in the database, re-synced and deleted cohorts.

@Zaimwa9
Zaimwa9 requested review from a team as code owners August 14, 2026 14:33
@Zaimwa9
Zaimwa9 requested review from Holmus and gagantrivedi and removed request for a team August 14, 2026 14:33
@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 25, 2026 9:19am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
flagsmith-frontend-preview Ignored Ignored Preview Aug 25, 2026 9:19am
flagsmith-frontend-staging Ignored Ignored Preview Aug 25, 2026 9:19am

Request Review

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d522df87-28de-459f-9d25-37de289fbd50

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds multipart CSV synchronisation for cohorts. The change validates CSV size and content, extracts identifiers, updates memberships in batches, tracks ignored rows, increments cohort versions, and queues delta application. Cohort creation now accepts and persists metadata. Segment responses expose related cohort details. The change adds metrics, event catalogue entries, tests, and OpenAPI schemas.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: 🟠 High · up to aa61a

The CSV synchronization feature can strand membership updates, accept identifiers that downstream processing cannot handle, or leave external membership state inconsistent with the database under concurrent sync and application. These correctness and data-integrity risks make the PR unsafe to merge until the synchronization and validation paths are fixed.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added api Issue related to the REST API docs Documentation updates feature New feature or request and removed docs Documentation updates labels Aug 14, 2026
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-e2e:pr-8294 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api-test:pr-8294 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api:pr-8294 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-8294 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-8294 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-frontend:pr-8294 Finished ✅ Results

@Zaimwa9

Zaimwa9 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@themis-blindfold review

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor
✅ private-cloud · depot-ubuntu-latest-16 — run #19704 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  54.8 seconds
commit  9fbfb13
info  🔄 Run: #19704 (attempt 1)

🗂️ Previous results
✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19704 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  4 passed

Details

stats  4 tests across 3 suites
duration  1 minute, 2 seconds
commit  9fbfb13
info  🔄 Run: #19704 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19704 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  40.8 seconds
commit  9fbfb13
info  🔄 Run: #19704 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19704 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  33.5 seconds
commit  9fbfb13
info  🔄 Run: #19704 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19700 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  4 passed

Details

stats  4 tests across 4 suites
duration  1 minute, 1 second
commit  065d967
info  🔄 Run: #19700 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #19700 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  3 passed

Details

stats  3 tests across 3 suites
duration  32.6 seconds
commit  065d967
info  🔄 Run: #19700 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19702 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  39.4 seconds
commit  232f6a7
info  🔄 Run: #19702 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19700 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  45.1 seconds
commit  065d967
info  🔄 Run: #19700 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19702 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  41.5 seconds
commit  232f6a7
info  🔄 Run: #19702 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19700 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  41.4 seconds
commit  065d967
info  🔄 Run: #19700 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19370 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  38.9 seconds
commit  3a5f36a
info  🔄 Run: #19370 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #19370 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  35 seconds
commit  3a5f36a
info  🔄 Run: #19370 (attempt 1)

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Visual Regression

19 screenshots compared. See report for details.
View full report

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6fc61ada-1f5d-43a2-8a9d-94781de30573

📥 Commits

Reviewing files that changed from the base of the PR and between 05b2fcf and aa61a35.

📒 Files selected for processing (17)
  • api/cohorts/constants.py
  • api/cohorts/dataclasses.py
  • api/cohorts/exceptions.py
  • api/cohorts/metrics.py
  • api/cohorts/serializers.py
  • api/cohorts/services.py
  • api/cohorts/views.py
  • api/segments/serializers.py
  • api/segments/views.py
  • api/tests/unit/cohorts/conftest.py
  • api/tests/unit/cohorts/test_services.py
  • api/tests/unit/cohorts/test_views.py
  • api/tests/unit/segments/test_unit_segments_views.py
  • docs/docs/deployment-self-hosting/observability/_events-catalogue.md
  • docs/docs/deployment-self-hosting/observability/_metrics-catalogue.md
  • mcp/src/flagsmith_mcp/openapi.json
  • openapi.yaml

Comment thread api/cohorts/services.py Outdated
Comment thread api/cohorts/services.py Outdated
Comment thread api/cohorts/services.py Outdated
Comment thread openapi.yaml
Comment thread openapi.yaml
@themis-blindfold

Copy link
Copy Markdown
Contributor

⚖️ Themis review: ✅ Ship it

Clean, well-structured addition of the CSV sync endpoint and cohort summary on segments. The delta computation in sync_cohort_memberships_from_csv correctly handles all membership state transitions (new adds, re-adds of pending removals, discards of unapplied pending adds, removal of applied members), and the select_for_update lock on the cohort serialises concurrent syncs. Tests are thorough: parametrised extraction covering headers, multi-column, quoted values, BOM, duplicates, empty rows, and too-long identifiers; plus full delta-semantics tests for the sync service and permission/validation tests for the view.

Area Score
🎯 Correctness 5/5
🧪 Test coverage 5/5
📐 Code quality 4/5
🚀 Product impact 4/5
📝 Walkthrough
  • CSV sync endpoint (cohorts/views.py, cohorts/services.py) - New POST .../cohorts/{id}/sync-csv/ action with multipart upload; parses the CSV, computes a membership delta against existing rows, creates/updates/deletes CohortMembership rows inside a locked transaction, bumps the cohort version, and enqueues the applier task.
  • CSV extraction (cohorts/services.py) - extract_identifiers_from_csv handles BOM stripping, configurable identifier column, header skipping, deduplication, empty/too-long filtering, and wraps csv.Error into a ValidationError.
  • Serializer & validation (cohorts/serializers.py) - CohortCsvSyncSerializer validates the uploaded file against the 10 MB size cap; CohortSerializer now accepts optional metadata on create and validates required metadata fields against the managed segment's content type.
  • Cohort summary on segments (segments/serializers.py, segments/views.py) - SegmentSerializer gains a read-only cohort field via SerializerMethodField, backed by a prefetch on the list queryset. _SegmentCohortSerializer exposes id, environment, source_type, version, and deletion_requested_at.
  • Observability (cohorts/metrics.py, docs) - New flagsmith_cohorts_csv_syncs_total counter and flagsmith_cohorts_csv_sync_identifiers histogram; cohorts.csv.synced structured log event. Docs catalogues updated with new entries and corrected line numbers.
  • OpenAPI / MCP spec - openapi.yaml and mcp/openapi.json updated with the new endpoint, _SegmentCohort schema, SourceTypeEnum, and the cohort field on segment schemas.
🧪 How to verify
  1. Run the new unit tests: pytest api/tests/unit/cohorts/test_services.py api/tests/unit/cohorts/test_views.py api/tests/unit/segments/test_unit_segments_views.py -k "csv or cohort".
  2. POST a multipart CSV to /api/v1/environments/{key}/cohorts/{id}/sync-csv/ and confirm a 202 with correct added/removed/unchanged/ignored counts.
  3. Re-upload a different CSV to the same cohort and verify the delta: removed identifiers move to pending_remove, new ones appear as pending_add, and the version increments.
  4. GET /api/v1/projects/{id}/segments/ and confirm each cohort-managed segment includes a cohort summary with source_type, version, and deletion_requested_at; non-cohort segments return cohort: null.
  5. Verify permissions: a user with only VIEW_ENVIRONMENT (no MANAGE_SEGMENTS) receives 403 on sync-csv.

Product take: This closes the loop on CSV-based cohort management by giving the dashboard everything it needs to upload, re-sync, and display cohort membership. Solid capability addition that unlocks the full create-from-CSV workflow.

🧭 Assumptions & unverified claims
  • The task processor stores tasks in the database, so .delay() inside transaction.atomic() is transaction-safe (task becomes visible only after commit). This is consistent with usage across the codebase but could not be verified against the task processor source in this environment.
  • SoftDeleteExportableModel's default manager filters out records with deleted_at IS NOT NULL, so segment.cohorts.all() correctly excludes fully deleted cohorts while including those pending drain.

A CSV walks into a bar; the parser orders one identifier, neat — no duplicates, no empties, hold the BOM. · reviewed at aa61a35

@Zaimwa9
Zaimwa9 force-pushed the feat/create-segment-from-csv branch from 05b2fcf to 033c67d Compare August 14, 2026 14:48
@Zaimwa9
Zaimwa9 requested a review from a team as a code owner August 14, 2026 14:48
@Zaimwa9
Zaimwa9 requested review from talissoncosta and removed request for a team August 14, 2026 14:48
@Zaimwa9
Zaimwa9 force-pushed the feat/cohort-csv-sync branch from aa61a35 to 4083994 Compare August 14, 2026 14:49
@github-actions github-actions Bot removed the feature New feature or request label Aug 14, 2026
@Zaimwa9
Zaimwa9 force-pushed the feat/cohort-csv-sync branch from 71a387d to 3a5f36a Compare August 14, 2026 15:55
@github-actions github-actions Bot added feature New feature or request docs Documentation updates and removed feature New feature or request docs Documentation updates labels Aug 14, 2026
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (feat/create-segment-from-csv@74e5d3c). Learn more about missing BASE report.

Additional details and impacted files
@@                       Coverage Diff                       @@
##             feat/create-segment-from-csv    #8294   +/-   ##
===============================================================
  Coverage                                ?   98.76%           
===============================================================
  Files                                   ?     1586           
  Lines                                   ?    63514           
  Branches                                ?        0           
===============================================================
  Hits                                    ?    62730           
  Misses                                  ?      784           
  Partials                                ?        0           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Holmus
Holmus removed their request for review August 17, 2026 07:53
Comment thread api/cohorts/services.py Outdated
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request docs Documentation updates labels Aug 25, 2026
@github-actions github-actions Bot added the docs Documentation updates label Aug 25, 2026
@Zaimwa9
Zaimwa9 force-pushed the feat/cohort-csv-sync branch from 232f6a7 to 9fbfb13 Compare August 25, 2026 09:19
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request docs Documentation updates labels Aug 25, 2026
gagantrivedi
gagantrivedi previously approved these changes Aug 25, 2026
@Zaimwa9 Zaimwa9 closed this Aug 25, 2026
@Zaimwa9
Zaimwa9 force-pushed the feat/cohort-csv-sync branch from 9fbfb13 to 27adf8f Compare August 25, 2026 09:48
@Zaimwa9
Zaimwa9 merged commit 27adf8f into main Aug 25, 2026
@Zaimwa9
Zaimwa9 force-pushed the feat/create-segment-from-csv branch from 74e5d3c to f1948e1 Compare August 25, 2026 09:48
@Zaimwa9
Zaimwa9 deleted the feat/cohort-csv-sync branch August 25, 2026 09:48
@Zaimwa9
Zaimwa9 changed the base branch from feat/create-segment-from-csv to main August 25, 2026 09:48
@Zaimwa9
Zaimwa9 dismissed gagantrivedi’s stale review August 25, 2026 09:48

The base branch was changed.

@Zaimwa9
Zaimwa9 restored the feat/cohort-csv-sync branch August 25, 2026 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants